/*-
 * Copyright (c) 2014 Shang-Rong Cai. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $ DIDF: did.h    Rev. 0.1.1    2014-04-17T23:32+08:00 $
 */

#include <stdint.h>
#include <stdio.h>

/* Dual Indexed Data File Format */
#ifndef DID_H
#define DID_H

/* Locally Error Code */
#ifndef ERRNO_UNDEFINED
#define ERRNO_UNDEFINED 0  /* No error occurred */
#endif

#ifndef ERRNO_UNKNOWN_TYPE
#define ERRNO_UNKNOWN_TYPE 285  /* Unknown type identifier */
#endif

#define ERRNO_ENDIAN 1000


/* Index Type */
#define DID_HEAD_INDEX_T_I32 0x04
#define DID_HEAD_INDEX_T_I64 0x08

/* Data Entry Type */
#define DID_HEAD_DATA_T_F32 0x01
#define DID_HEAD_DATA_T_F64 0x02
#define DID_HEAD_DATA_T_C32 0x03
#define DID_HEAD_DATA_T_C64 0x04
#define DID_HEAD_DATA_T_I32 0x05
#define DID_HEAD_DATA_T_I64 0x06

/* File Identify And Version Information */
static const char cntstr_did_idc[] = "DID     ";
static const char cntstr_did_num[] = "  0 1  0";
static const char cntstr_did_tag[] = "ALPHA   ";

/* Address Offset */
#define DID_ADDR_OFFSET_HEAD   0
#define DID_ADDR_OFFSET_META  64
#define DID_ADDR_OFFSET_BODY 128

/* Endian Type */
#define DID_HEAD_ENDIAN_LITTLE 0x0001020304050607L
#define DID_HEAD_ENDIAN_BIG    0x0706050403020100L

/* Length/Size */
#define DID_HEAD_IDC_SIZE 8
#define DID_HEAD_NUM_SIZE 8
#define DID_HEAD_TAG_SIZE 8


/* Head Part */
typedef struct
{
    char identify[DID_HEAD_IDC_SIZE];  /* File identify */
    uint8_t index_type;  /* Index type */
    uint8_t entry_type;  /* Data entry type */
    uint64_t endian_type;  /* Endianness type */
    char ver_num[DID_HEAD_NUM_SIZE];  /* Version number */
    char ver_tag[DID_HEAD_TAG_SIZE];  /* Version tag */
} did_head_t;

extern int did_head_set_info(did_head_t *hdprt, const uint8_t idxtyp, const uint8_t enttyp);

extern int did_head_stdout(const did_head_t *hdprt);


/* Meta Part */
typedef struct
{
    uint64_t fst_idx_sz;  /* First index bound */
    uint64_t snd_idx_sz;  /* Second index bound */
    uint64_t dat_ent_sz;  /* Number of data entry */

    uint64_t fst_idx_dst_addr;  /* Address for first index depended distribution */
    uint64_t idx_dat_lst_addr;  /* Address for indexed data entry list */

    uint64_t snd_idx_dst_addr;  /* Address for second index depended distribution */
    uint64_t idx_shf_lst_addr;  /* Address for index and offset list */
} did_meta_t;

extern int did_meta_set_info(did_meta_t *mtprt, const did_head_t *hdprt, const uint64_t fiz, const uint64_t siz, const uint64_t dez);

extern int did_meta_stdout(const did_meta_t *mtprt);


/* Body Part */
typedef struct
{
    void *fst_dst;  /* Distribution of indexed data depended on first index */
    void *ide_lst;  /* Indexed data entry list */

    void *snd_dst;  /* Distribution of index and offset depended on second index */
    void *iao_lst;  /* Index and offset list */
} did_body_t;

extern int did_body_create(did_body_t *bdprt, const did_head_t *hdprt, const did_meta_t *mtprt, const void *fst_idx_lst, const void *snd_idx_lst, const void *dat_ent_lst);

extern int did_body_delete(did_body_t *bdprt);


extern int did_read_head(FILE *fpif, did_head_t *hdprt);

extern int did_read_meta(FILE *fpif, did_meta_t *mtprt);


extern int did_read_body_fiwise(FILE *fpif, void *dst, void *idx, void *val);

extern int did_read_body_siwise(FILE *fpif, void *dst, void *idx, void *val);


extern int did_write(FILE *fpof, const did_head_t *hdprt, const did_meta_t *mtprt, const did_body_t *bdprt);

#endif
